package server.startup;

import server.*;
import server.core.StandardWrapper;
import server.xml.*;

import java.util.List;
import java.util.Map;

public class ContextConfig implements LifecycleListener {
    private Context context = null;

    private void log(String message) {
        Logger logger = null;
        if (context != null)
            logger = context.getLogger();
        if (logger != null)
            logger.log("ContextConfig[" + context.getName() + "]: " + message);
        else
            System.out.println("ContextConfig[" + context.getName() + "]: " + message);
    }

    private void log(String message, Throwable throwable) {
        Logger logger = null;
        if (context != null)
            logger = context.getLogger();
        if (logger != null)
            logger.log("ContextConfig[" + context.getName() + "] " + message, throwable);
        else {
            System.out.println("ContextConfig[" + context.getName() + "]: " + message);
            throwable.printStackTrace(System.out);
        }
    }
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        try {
            context = (Context)event.getLifecycle();
        } catch (Throwable t) {
            return;
        }
        if (Lifecycle.START_EVENT.equals(event.getType())) {
            contextConfig();
        }
    }

    private void contextConfig() {
        context.setConfigured(true);
        ServerXml serverXml = null;
        WebXml defaultWebXml = null;
        WebXml webXml = null;

        try {
            serverXml = ServerXmlUtil.getServerXml();
        } catch (Throwable t) {
            log("server.xml配置文件出错", t);
            context.setConfigured(false);
            return;
        }

        try {
            defaultWebXml = WebXmlUtil.getDefaultWebXml();
        } catch (Throwable t) {
            log("默认的web.xml配置文件出错", t);
            context.setConfigured(false);
            return;
        }

        try {
            webXml = WebXmlUtil.parse(context.getName());
        } catch (Throwable t) {
            log("本应用的web.xml配置文件出错", t);
            context.setConfigured(false);
            return;
        }

        configServerXml(serverXml);

        configWebXml(defaultWebXml);
        configWebXml(webXml);
        configstaticResourcesWrapper();

    }

    private void configstaticResourcesWrapper() {
        Wrapper staticResourcesWrapper = new StandardWrapper();
        staticResourcesWrapper.setName("---server.servlet.StaticResourcesProcessor");
        staticResourcesWrapper.setServletClass("server.servlet.StaticResourcesProcessor");

        String[] welcomeFiles = context.findWelcomeFiles();
        if (welcomeFiles != null) {
            staticResourcesWrapper.addInitParameter("welcomeFileCount", "" + welcomeFiles.length);
            for (int i = 0; i < welcomeFiles.length; i++) {
                staticResourcesWrapper.addInitParameter("welcomeFile" + i, welcomeFiles[i]);
            }
        }
        context.addChild(staticResourcesWrapper);
        context.setStaticResourcesWrapper(staticResourcesWrapper);
    }

    private void configServerXml(ServerXml serverXml) {
        boolean reloadable = serverXml.isReloadable();
        int checkInterval = serverXml.getCheckInterval();
        context.setReloadable(reloadable);
        Loader loader = context.getLoader();
        if (loader != null) {
            loader.setCheckInterval(checkInterval);
        }
    }
    private void configWebXml(WebXml webXml) {
        if (webXml == null)
            return;
        sessionConfig(webXml);
        welcomeFileListConfig(webXml);
        listenerConfig(webXml);
        filterConfig(webXml);
        servletConfig(webXml);
        errorPageConfig(webXml);
    }

    private void sessionConfig(WebXml webXml) {
        int sessionTimeout = webXml.getSessionTimeout();
        context.setSessionTimeout(sessionTimeout);
        Manager manager = context.getManager();
        if (manager != null)
            manager.setMaxInactiveInterval(sessionTimeout * 60);
    }

    private void welcomeFileListConfig(WebXml webXml) {
        List<String> welcomeFileList = webXml.getWelcomeFileList();
        for (String welcomeFile : welcomeFileList)
            context.addWelcomeFile(welcomeFile);
    }

    private void listenerConfig(WebXml webXml) {
        List<String> listeners = webXml.getListeners();
        for (String listener : listeners) {
            context.addApplicationListener(listener);
        }
    }
    private void filterConfig(WebXml webXml) {
        List<FilterDef> filterDefs = webXml.getFilterDefs();
        List<FilterMap> filterMappings = webXml.getFilterMappings();
        for (FilterDef filterDef : filterDefs)
            context.addFilterDef(filterDef);
        for (FilterMap filterMap : filterMappings)
            context.addFilterMap(filterMap);
    }
    private void servletConfig(WebXml webXml) {
        List<ServletDef> servletDefs = webXml.getServletDefs();
        for (ServletDef servletDef : servletDefs) {
            StandardWrapper wrapper = new StandardWrapper();
            wrapper.setName(servletDef.getServletName());
            wrapper.setServletClass(servletDef.getServletClass());
            Map<String, String> params = servletDef.getInitParams();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                wrapper.addInitParameter(entry.getKey(), entry.getValue());
            }
            context.addChild(wrapper);
        }

        List<ServletMap> servletMappings = webXml.getServletMappings();
        for (ServletMap servletMap : servletMappings) {
            String servletName = servletMap.getServletName();
            List<String> urlPatterns = servletMap.getUrlPatterns();
            if (servletName == null)
                continue;
            for (String urlPattern : urlPatterns)
                context.addServletMapping(urlPattern, servletName);
        }
    }

    private void errorPageConfig(WebXml webXml) {
        Map<Integer, String> errorPages = webXml.getErrorPages();
        for (Map.Entry<Integer, String> entry : errorPages.entrySet())
            context.addErrorPage(entry.getKey(), entry.getValue());
    }

}
